import re
import json
import random
import logging
from django.contrib.auth.models import AnonymousUser
from django.contrib.auth import login, logout, authenticate
from django.http import HttpResponse
from django_redis import get_redis_connection
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from rest_framework.permissions import AllowAny

from aijia_project.captcha.captcha import captcha
from aijia_project.utils.Error_statuscode import ErrorCode
from users.models import User
from users.utils import constants
from aijia_project.qiniuyun.upload_image import upload_image2QINIU

# from .tasks import send_sms

# 初始化日志器
logger = logging.getLogger('django')


# api/v1.0/users/
class RegisterView(GenericAPIView):
    """用户注册视图类"""

    # 允许所有用户访问
    permission_classes = (AllowAny,)

    def post(self, request):
        """用户注册"""
        mobile = request.data.get('mobile')
        phonecode = request.data.get('phonecode')
        password = request.data.get('password')

        # 判断参数是否齐全
        if not all([password, phonecode, mobile]):
            return Response({"errno": ErrorCode.PARAMERR, 'errmsg': '缺少必传参数'})
        # 判断密码是否是8-20个数字
        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return Response({"errno": ErrorCode.PARAMERR, 'errmsg': '密码不是8~20位数字字母'})
        try:
            User.objects.get(username=mobile)
            return Response({"errno": ErrorCode.DATAERR, 'errmsg': '用户名重复'})
        except Exception:
            # 读取redis中的短信验证码
            redis_cli = get_redis_connection('sms_code')
            sms_code_redis = redis_cli.get(mobile)
            # 2.判断是否过期
            if sms_code_redis is None:
                return Response({"errno": ErrorCode.DATAERR, 'errmsg': '短信验证码已经过期'})
            # 3.删除短信验证码，不可以使用第二次
            redis_cli.delete(mobile)
            # 4.判断是否正确
            if sms_code_redis.decode() != phonecode:
                return Response({"errno": ErrorCode.DATAERR, 'errmsg': '验证码错误'})
            # 处理
            # 1.创建用户对象
            user = User.objects.create_user(
                username=mobile,
                mobile=mobile,
                password=password,
                real_name="未激活用户" + str(mobile),
                avatar='http://q0jf9a5hr.bkt.clouddn.com/%E9%BB%98%E8%AE%A4%E5%A4%B4%E5%83%8F.png'
            )
            # 2.状态保持
            login(request, user)

            return Response({
                "errno": "0",
                "errmsg": "注册成功"
            })


# api/v1.0/imagecode/
class ImageCodeView(GenericAPIView):
    """图形验证码视图类"""

    # 允许所有用户访问
    permission_classes = (AllowAny,)

    def get(self, request):
        cur = request.GET.get('cur')
        pre = request.GET.get('pre')

        # 生成图片的文本、数据
        code, image = captcha.generate_captcha()
        logger.info(code)

        # 在Redis中存储图形验证码的文字信息
        redis_cli = get_redis_connection('image_code')
        # 立即删除redis中图形验证码表示这个值不能使用第二次
        if pre:
            redis_cli.delete(pre)
        redis_cli.setex(cur, constants.IMAGE_CODE_EXPIRES, code)

        # 响应验证码图片
        return HttpResponse(image, content_type='image/png')


class SmsCodeView(GenericAPIView):
    """短信验证码视图类"""

    # 允许所有用户访问
    permission_classes = (AllowAny,)

    def post(self, request):
        # 接收
        json_dict = json.loads(request.body.decode())
        mobile = json_dict.get('mobile')
        id = json_dict.get('id')
        text = json_dict.get('text')
        # 验证
        redis_cli_sms = get_redis_connection('sms_code')

        # 1.非空
        if not all([mobile, id, text]):
            return Response({"code": 4103, 'errmsg': '参数不完整'})
        # 2.图形验证码是否正确
        # 2.1从redis中读取之前保存的图形验证码文本
        redis_cli_image = get_redis_connection('image_code')
        image_code_redis = redis_cli_image.get(id)
        # 2.2如果redis中的数据过期则提示
        if image_code_redis is None:
            return Response({'code': 4103, 'errmsg': '图形验证码已过期，点击图片换一个'})
        # 2.3立即删除redis中图形验证码，表示这个值不能使用第二次
        redis_cli_image.delete(id)
        # 2.3对比图形验证码：不区分大小写
        if image_code_redis.decode().lower() != text.lower():
            return Response({'code': 4103, 'errmsg': '图形验证码错误'})
        if redis_cli_sms.get(mobile + '_flag'):
            return Response({'code': 4201, 'errmsg': '发送短信过于频繁'})

        # 处理
        # 1.生成随机6位数
        sms_code = '%06d' % random.randint(0, 999999)
        logger.info(sms_code)
        # 优化：使用管道
        redis_pl = redis_cli_sms.pipeline()
        # # 2.1存入redis
        redis_pl.setex(mobile, constants.SMS_CODE_EXPIRES, sms_code)
        # 2.2写发送标记
        redis_pl.setex(mobile + '_flag', constants.SMS_CODE_FLAG, 1)
        redis_pl.execute()

        # 3.发短信
        # ccp = CCP()
        # ccp.send_template_sms(mobile, [sms_code, constants.SMS_CODE_EXPIRES / 60], 1)
        # 通过delay调用，可以将任务加到队列中，交给celery去执行
        # send_sms.delay(mobile, sms_code)

        # 响应
        return Response({
            "errno": "0",
            "errmsg": "发送成功"
        })


# /api/v1.0/session
class LoginView(GenericAPIView):
    """登录视图类"""

    # 允许所有用户访问
    permission_classes = (AllowAny,)

    def get(self, request):
        """判断用户是否登录"""
        user = request.user
        # 如果用户未登录，user是匿名用户类AnonymousUser
        if not isinstance(user, AnonymousUser):
            return Response({
                "errno": ErrorCode.OK,
                "errmsg": "已登录",
                "data": {
                    "user_id": user.id,
                    "name": user.real_name
                }
            })
        else:
            return Response({"errno": ErrorCode.SESSIONERR, "errmsg": "未登录"})

    def post(self, request):
        """用户登录"""
        mobile = request.data.get('mobile')
        password = request.data.get('password')

        # 参数校验
        if not all([mobile, password]):
            return Response({"errno": ErrorCode.PARAMERR, 'errmsg': '缺少手机号或密码！'})
        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return Response({"errno": ErrorCode.PARAMERR, 'errmsg': '密码格式不正确！'})

        # 根据用户输入的账密去数据库中找到要登录的账号
        user = authenticate(username=mobile, password=password)
        if user is None:
            return Response({"errno": ErrorCode.LOGINERR, 'errmsg': '账密不正确'})

        # 登录并且状态保持
        login(request, user)
        # 登录状态保持到用户关闭浏览器
        request.session.set_expiry(0)

        return Response({"errno": ErrorCode.OK, "errmsg": "登录成功"})

    def delete(self, request):
        """退出登录"""
        # 登出
        logout(request)

        return Response({"errno": ErrorCode.OK, "errmsg": "已登出"})


# api/v1.0/user/auth
class AuthView(GenericAPIView):
    """用户实名认证视图类"""

    def get(self, request):
        """获得用户实名认证信息"""
        real_name = request.user.real_name
        id_card = request.user.id_card

        # 判断用户是否进行了实名认证
        if not all([real_name, id_card]):
            return Response({"errno": ErrorCode.USERERR, 'errmsg': '用户未完成实名认证！'})
        else:
            return Response({
                "data": {
                    "real_name": real_name,
                    "id_card": id_card
                },
                "errno": ErrorCode.OK,
                'errmsg': '用户已完成实名认证！'
            })

    def post(self, request):
        """用户实名认证"""
        # 接收参数
        real_name = request.data.get('real_name')
        id_card = request.data.get('id_card')

        # 校验参数
        if not all([real_name, id_card]):
            return Response({"errno": ErrorCode.PARAMERR, 'errmsg': '参数不全！'})
        if not re.match(r'^[\u4e00-\u9fa5]{2,24}$', real_name):
            return Response({"errno": ErrorCode.PARAMERR, 'errmsg': '真实姓名格式有误！'})
        if not re.match(r'^[\d]{18}$', id_card):
            return Response({"errno": ErrorCode.PARAMERR, 'errmsg': '身份证号格式有误！'})

        # 在数据库中保存数据
        user = request.user
        user.real_name = real_name
        user.id_card = id_card
        try:
            user.save()
        except Exception as e:
            logger.error(e)
            return Response({"errno": ErrorCode.DATAERR, 'errmsg': '数据库错误——实名认证失败'})

        # 响应认证结果
        return Response({"errno": ErrorCode.OK, 'errmsg': '认证信息保存成功'})


# /api/v1.0/user/name
class UsernameView(GenericAPIView):
    """用户名修改视图类"""

    def put(self, request):
        # 接收参数
        new_name = request.data.get('name')
        user = request.user

        # 校验参数
        if not new_name:
            return Response({"errno": ErrorCode.PARAMERR, "errmsg": "用户名不能为空！"})

        # 在数据库中保存新用户名
        user.username = new_name
        try:
            user.save()
        except Exception as e:
            logger.error(e)
            return Response({"errno": ErrorCode.DATAERR, 'errmsg': '数据库错误——更改用户名失败'})

        # 响应修改结果
        return Response({"errno": ErrorCode.OK, 'errmsg': '修改成功'})


class AvatarView(GenericAPIView):
    """用户头像上传视图类"""

    def post(self, request):
        # avatar是InMemoryUploadedFile类的实例
        avatar = request.data['avatar']
        # avatar的_name属性是图片的名字
        image_name = avatar._name
        # image是Bytes类型的图片
        image = avatar.file.read()
        # 上传图片至七牛云并且得到图片的url
        image_url = upload_image2QINIU(image, image_name)

        # 在数据库中存储用户的头像
        try:
            user = request.user
            user.avatar = image_url
            user.save()
        except Exception as e:
            logger.error(e)

        return Response({
            "data":
                {
                    "avatar_url": image_url
                },
            "errno": ErrorCode.OK,
            "errmsg": "头像上传成功"
        })


# /api/v1.0/user
class UserInfoView(GenericAPIView):
    """用户中心视图类"""

    def get(self, request):
        """用户中心界面"""
        user = request.user
        return Response({
            "data": {
                "avatar_url": user.avatar.url,
                "create_time": user.date_joined,
                "mobile": user.mobile,
                "name": user.username,
                "user_id": user.id,
            },
            "errmsg": "OK",
            "errno": ErrorCode.OK
        })
